import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class PrintABC {
    public static void main(String[] args) {
        Print print = new Print();
        CountDownLatch latch = new CountDownLatch(1);
        MyThreadA myThreadA = new MyThreadA(latch,print);
        MyThreadB myThreadB = new MyThreadB(latch,print);
        MyThreadC myThreadC = new MyThreadC(latch,print);
        for (int i = 0; i < 15; i++) {
            new Thread(myThreadA,"AAA "+i).start();
            new Thread(myThreadB,"BBB "+i).start();
            new Thread(myThreadC,"CCC "+i).start();
        }
        latch.countDown();
        System.out.println("----------------------------");
    }
}
class MyThreadA implements Runnable{
    private CountDownLatch latch;
    private Print print;

    public MyThreadA(CountDownLatch latch,Print print) {
        this.latch = latch;
        this.print = print;
    }
    @Override
    public void run() {
        try {
            latch.await();
            print.outA();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

class MyThreadB implements Runnable{
    private CountDownLatch latch;
    private Print print;

    public MyThreadB(CountDownLatch latch,Print print) {
        this.latch = latch;
        this.print = print;
    }
    @Override
    public void run() {
        try {
            latch.await();
            print.outB();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}
class MyThreadC implements Runnable{
    private CountDownLatch latch;
    private Print print;

    public MyThreadC(CountDownLatch latch,Print print) {
        this.latch = latch;
        this.print = print;
    }
    @Override
    public void run() {
        try {
            latch.await();
            print.outC();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}
class Print {

    int num = 1;
    Lock lock = new ReentrantLock();
    Condition con1 = lock.newCondition();
    Condition con2 = lock.newCondition();
    Condition con3 = lock.newCondition();

    public void outA() {
        lock.lock();
        try {
            while (num != 1) {
                con1.await();
            }
            System.out.println(Thread.currentThread().getName() + ":   A");
            num = 2;
            con2.signal();
        } catch (Exception e) {

        } finally {
            lock.unlock();
        }
    }
    public void outB() {
        lock.lock();
        try {
            while (num != 2) {
                con2.await();
            }
            System.out.println(Thread.currentThread().getName() + ":   B");
            num = 3;
            con3.signal();
        } catch (Exception e) {

        } finally {
            lock.unlock();
        }
    }
    public void outC() {
        lock.lock();
        try {
            while (num != 3) {// if 引起虚假唤醒
                con3.await();
            }
            System.out.println(Thread.currentThread().getName() + ":   C");
            num = 1;
            con1.signal();
        } catch (Exception e) {

        } finally {
            lock.unlock();
        }
    }
}